﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Interpreter
{

    //用于存储操作符号
    public class OperCharExpression : Expression
    {
        private string operChar;

        public string OperChar
        {
            get { return operChar; }
        }

        public OperCharExpression(string oper)
        {
            this.operChar = oper;
        }

        public override float Call(Dictionary<string, float> keyValues)
        {
            throw new NotImplementedException();
        }
    }
    //运算符解释器
    public class OPerExpression : Expression
    {
        protected Expression leftExpre;
        protected Expression rightExpre;

        public OPerExpression(Expression left, Expression right)
        {
            this.leftExpre = left;
            this.rightExpre = right;
        }

        public override float Call(Dictionary<string, float> keyValues)
        {
            throw new NotImplementedException();
        }
    }
    //加号运算
    [Description("+")]
    public class AddExpression : OPerExpression
    {
        public AddExpression(Expression left, Expression right) : base(left, right)
        {

        }

        public override float Call(Dictionary<string, float> keyValues)
        {
            return this.leftExpre.Call(keyValues) + this.rightExpre.Call(keyValues);
        }
    }

    //减号运算
    [Description("-")]
    public class SubExpression : OPerExpression
    {
        public SubExpression(Expression left, Expression right) : base(left, right)
        {
        }

        public override float Call(Dictionary<string, float> keyValues)
        {
            return this.leftExpre.Call(keyValues) - this.rightExpre.Call(keyValues);
        }
    }
    //除号运算
    [Description("/")]
    public class DivExpression : OPerExpression
    {
        public DivExpression(Expression left, Expression right) : base(left, right)
        {
        }
        public override float Call(Dictionary<string, float> keyValues)
        {
            return (float)(this.leftExpre.Call(keyValues) * 1.0 / rightExpre.Call(keyValues));
        }
    }

    [Description("*")]
    public class MulExpression : OPerExpression
    {
        public MulExpression(Expression left, Expression right) : base(left, right)
        {
        }
        public override float Call(Dictionary<string, float> keyValues)
        {
            return leftExpre.Call(keyValues)*rightExpre.Call(keyValues);
        }
    }

    [Description("^")]
    public class CubeExpression : OPerExpression
    {
        public CubeExpression(Expression left, Expression right) : base(left, right)
        {
        }

        public override float Call(Dictionary<string, float> keyValues)
        {
            return (float)Math.Pow(leftExpre.Call(keyValues), (int)rightExpre.Call(keyValues));
        }
    }

    public enum OperEnum
    {
        [Priority(0)]
        [Description("null")]
        Null,
        [Priority(1)]
        [Description("+")]
        Add,
        [Priority(1)]
        [Description("-")]
        Sub,
        [Priority(2)]
        [Description("/")]
        Div,
        [Priority(2)]
        [Description("*")]
        Mul,

        [Priority(3)]
        [Description("^")]
        Cube,

    }

    public class PriorityAttribute : Attribute
    {
        private string description;

        public string Description
        {
            get { return description; }
        }

        private int prior;

        public int PriortyFlag
        {
            get { return prior; }
        }


        public PriorityAttribute(string des, int pro) : this(pro)
        {
            this.description = des;
        }

        public PriorityAttribute(int pro)
        {
            this.prior = pro;
        }
    }


    public class AssemClass
    {
        public static T GetTypeByName<T>(string str, params object[] objs)
        {
            T tVal = default(T);
            Assembly curAssembly = Assembly.GetExecutingAssembly();
            Type[] typeArr = curAssembly.GetTypes();
            foreach (Type type in typeArr)
            {
                object[] obs = type.GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (obs != null && obs.Length > 0)
                {
                    string valStr = ((DescriptionAttribute)obs[0]).Description;
                    if (valStr == str)
                    {
                        try
                        {
                            tVal = (T)Activator.CreateInstance(type, objs);
                        }
                        catch (Exception ex)
                        {
                            tVal = default(T);
                            //记录异常日志
                            Console.WriteLine(ex.StackTrace + ex.Message);
                        }
                        break;
                    }
                }
            }
            return tVal;
        }

        /// <summary>
        /// 根据表达式得到绑定字典信息
        /// </summary>
        /// <param name="str">表达式</param>
        /// <param name="fuc">怎么获取值委托</param>
        /// <returns>如果字典的count为零 则认为解析失败</returns>
        public static Dictionary<string, float> GetDicInfoByExp(string str, Func<string, float> fuc)
        {
            Dictionary<string, float> dic = new Dictionary<string, float>();
            Regex regex = new Regex("[a-zA-Z]");
            if (string.IsNullOrEmpty(str))
            {
                return dic;
            }
            string singleStr = string.Empty;
            foreach (var item in str)
            {
                singleStr = item.ToString();
                if (regex.IsMatch(singleStr) && !dic.ContainsKey(singleStr))
                {
                    dic.Add(singleStr, fuc(singleStr));
                }
            }
            return dic;
        }

        /// <summary>
        /// 获取表达式中的最高优先级
        /// </summary>
        /// <param name="strVal">表达式</param>
        /// <returns></returns>
        public static int GetTopPriorityVal(string strVal)
        {
            int val = 0;
            string curStr = string.Empty;
            Type type = typeof(OperEnum);
            var fields = type.GetFields();
            Dictionary<string, FieldInfo> fieldInfoDic = new Dictionary<string, FieldInfo>();
            Type sysType = typeof(DescriptionAttribute);
            Type priorType = typeof(PriorityAttribute);
            foreach (var itemField in fields)
            {
                var objs = itemField.GetCustomAttributes(sysType, false);
                if (objs != null && objs.Length > 0)
                {
                    string fieldStr = ((DescriptionAttribute)objs[0]).Description;
                    if (!fieldInfoDic.ContainsKey(fieldStr))
                    {
                        fieldInfoDic.Add(fieldStr, itemField);
                    }
                }
            }

            foreach (var itemChar in strVal)
            {
                curStr = itemChar.ToString();
                if (fieldInfoDic.ContainsKey(curStr))
                {
                    var objs = fieldInfoDic[curStr].GetCustomAttributes(priorType, false);
                    if (objs != null && objs.Length > 0)
                    {
                        int prioNu = ((PriorityAttribute)objs[0]).PriortyFlag;
                        if (prioNu > val)
                        {
                            val = prioNu;
                        }
                    }
                }
            }
            return val;
        }

        public static int GetCurPriortyVal(string oper)
        {
            int val = 0;
            Type type = typeof(OperEnum);
            var fields = type.GetFields();
            Type priorType = typeof(PriorityAttribute);
            Type sysType = typeof(DescriptionAttribute);
            foreach (var itemField in fields)
            {
                var objs = itemField.GetCustomAttributes(sysType, false);
                if (objs != null && objs.Length > 0)
                {
                    string valStr = ((DescriptionAttribute)objs[0]).Description;
                    if (valStr== oper)
                    {
                        objs = itemField.GetCustomAttributes(priorType, false);
                        if (objs != null && objs.Length > 0)
                        {
                            val = ((PriorityAttribute)objs[0]).PriortyFlag;
                            break;
                        }
                    }
                }
            }
            return val;
        }
    }
}
